bitkeeper revision 1.1159.212.126 (42089d5esMXb54hvuQX14wvXnCm18w)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 8 Feb 2005 11:07:10 +0000 (11:07 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 8 Feb 2005 11:07:10 +0000 (11:07 +0000)
Various hypercall fixes for x86_64.
Main todos: 1. mmu_updates/update_va_mapping hypercalls.
            2. map perdomain_pt into Xen address space.
            3. exception/interrupt callbacks to guest OS.
            4. user-space ring 3 vs. guest-OS ring 3.
Signed-off-by: keir.fraser@cl.cam.ac.uk
xen/arch/x86/memory.c
xen/arch/x86/traps.c
xen/arch/x86/x86_32/mm.c
xen/arch/x86/x86_64/entry.S
xen/arch/x86/x86_64/mm.c
xen/include/asm-x86/mm.h
xen/include/asm-x86/multicall.h

index e9fa4b370eb7b81307003b76418d5dd7ba99d31c..36a146300193cb63da7c5c6de9e4dcc65efabcbb 100644 (file)
@@ -249,11 +249,13 @@ static inline void invalidate_shadow_ldt(struct exec_domain *d)
 
 static int alloc_segdesc_page(struct pfn_info *page)
 {
-    unsigned long *descs = map_domain_mem((page-frame_table) << PAGE_SHIFT);
+    struct desc_struct *descs;
     int i;
 
+    descs = map_domain_mem((page-frame_table) << PAGE_SHIFT);
+
     for ( i = 0; i < 512; i++ )
-        if ( unlikely(!check_descriptor(&descs[i*2])) )
+        if ( unlikely(!check_descriptor(&descs[i])) )
             goto fail;
 
     unmap_domain_mem(descs);
@@ -1651,6 +1653,182 @@ int do_update_va_mapping_otherdomain(unsigned long page_nr,
 
 
 
+/*************************
+ * Descriptor Tables
+ */
+
+void destroy_gdt(struct exec_domain *ed)
+{
+    int i;
+    unsigned long pfn;
+
+    for ( i = 0; i < 16; i++ )
+    {
+        if ( (pfn = l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i])) != 0 )
+            put_page_and_type(&frame_table[pfn]);
+        ed->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
+    }
+}
+
+
+long set_gdt(struct exec_domain *ed, 
+             unsigned long *frames,
+             unsigned int entries)
+{
+    struct domain *d = ed->domain;
+    /* NB. There are 512 8-byte entries per GDT page. */
+    int i = 0, nr_pages = (entries + 511) / 512;
+    struct desc_struct *vgdt;
+    unsigned long pfn;
+
+    /* Check the first page in the new GDT. */
+    if ( (pfn = frames[0]) >= max_page )
+        goto fail;
+
+    /* The first page is special because Xen owns a range of entries in it. */
+    if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
+    {
+        /* GDT checks failed: try zapping the Xen reserved entries. */
+        if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
+            goto fail;
+        vgdt = map_domain_mem(pfn << PAGE_SHIFT);
+        memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
+               NR_RESERVED_GDT_ENTRIES*8);
+        unmap_domain_mem(vgdt);
+        put_page_and_type(&frame_table[pfn]);
+
+        /* Okay, we zapped the entries. Now try the GDT checks again. */
+        if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
+            goto fail;
+    }
+
+    /* Check the remaining pages in the new GDT. */
+    for ( i = 1; i < nr_pages; i++ )
+        if ( ((pfn = frames[i]) >= max_page) ||
+             !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
+            goto fail;
+
+    /* Copy reserved GDT entries to the new GDT. */
+    vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
+    memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY, 
+           gdt_table + FIRST_RESERVED_GDT_ENTRY, 
+           NR_RESERVED_GDT_ENTRIES*8);
+    unmap_domain_mem(vgdt);
+
+    /* Tear down the old GDT. */
+    destroy_gdt(ed);
+
+    /* Install the new GDT. */
+    for ( i = 0; i < nr_pages; i++ )
+        ed->arch.perdomain_ptes[i] =
+            mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
+
+    SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
+    SET_GDT_ENTRIES(ed, entries);
+
+    return 0;
+
+ fail:
+    while ( i-- > 0 )
+        put_page_and_type(&frame_table[frames[i]]);
+    return -EINVAL;
+}
+
+
+long do_set_gdt(unsigned long *frame_list, unsigned int entries)
+{
+    int nr_pages = (entries + 511) / 512;
+    unsigned long frames[16];
+    long ret;
+
+    if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) ) 
+        return -EINVAL;
+    
+    if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
+        return -EFAULT;
+
+    LOCK_BIGLOCK(current->domain);
+
+    if ( (ret = set_gdt(current, frames, entries)) == 0 )
+    {
+        local_flush_tlb();
+        __asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
+    }
+
+    UNLOCK_BIGLOCK(current->domain);
+
+    return ret;
+}
+
+
+long do_update_descriptor(
+    unsigned long pa, unsigned long word1, unsigned long word2)
+{
+    unsigned long pfn = pa >> PAGE_SHIFT;
+    struct desc_struct *gdt_pent, d;
+    struct pfn_info *page;
+    struct exec_domain *ed;
+    long ret = -EINVAL;
+
+    d.a = (u32)word1;
+    d.b = (u32)word2;
+
+    LOCK_BIGLOCK(current->domain);
+
+    if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(&d) ) {
+        UNLOCK_BIGLOCK(current->domain);
+        return -EINVAL;
+    }
+
+    page = &frame_table[pfn];
+    if ( unlikely(!get_page(page, current->domain)) ) {
+        UNLOCK_BIGLOCK(current->domain);
+        return -EINVAL;
+    }
+
+    /* Check if the given frame is in use in an unsafe context. */
+    switch ( page->u.inuse.type_info & PGT_type_mask )
+    {
+    case PGT_gdt_page:
+        /* Disallow updates of Xen-reserved descriptors in the current GDT. */
+        for_each_exec_domain(current->domain, ed) {
+            if ( (l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[0]) == pfn) &&
+                 (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
+                 (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
+                goto out;
+        }
+        if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
+            goto out;
+        break;
+    case PGT_ldt_page:
+        if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
+            goto out;
+        break;
+    default:
+        if ( unlikely(!get_page_type(page, PGT_writable_page)) )
+            goto out;
+        break;
+    }
+
+    /* All is good so make the update. */
+    gdt_pent = map_domain_mem(pa);
+    memcpy(gdt_pent, &d, 8);
+    unmap_domain_mem(gdt_pent);
+
+    put_page_type(page);
+
+    ret = 0; /* success */
+
+ out:
+    put_page(page);
+
+    UNLOCK_BIGLOCK(current->domain);
+
+    return ret;
+}
+
+
+
 /*************************
  * Writable Pagetables
  */
index 4cf22f86d79555a3d2eb5ab71cb65dca32942957..301d7a765e788232eaf76004bcbfa465d25af360 100644 (file)
@@ -149,6 +149,11 @@ static inline int do_trap(int trapnr, char *str,
     if ( !GUEST_FAULT(regs) )
         goto xen_fault;
 
+#ifndef NDEBUG
+    if ( (ed->arch.traps[trapnr].address == 0) && (ed->domain->id == 0) )
+        goto xen_fault;
+#endif
+
     ti = current->arch.traps + trapnr;
     tb->flags = TBF_EXCEPTION;
     tb->cs    = ti->cs;
@@ -314,6 +319,11 @@ asmlinkage int do_page_fault(struct xen_regs *regs)
     if ( !GUEST_FAULT(regs) )
         goto xen_fault;
 
+#ifndef NDEBUG
+    if ( (ed->arch.traps[TRAP_page_fault].address == 0) && (d->id == 0) )
+        goto xen_fault;
+#endif
+
     propagate_page_fault(addr, regs->error_code);
     return 0; 
 
@@ -523,6 +533,12 @@ asmlinkage int do_general_protection(struct xen_regs *regs)
         return 0;
 #endif
 
+#ifndef NDEBUG
+    if ( (ed->arch.traps[TRAP_gp_fault].address == 0) &&
+         (ed->domain->id == 0) )
+        goto gp_in_kernel;
+#endif
+
     /* Pass on GPF as is. */
     ti = current->arch.traps + 13;
     tb->flags      = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
@@ -838,6 +854,13 @@ long do_fpu_taskswitch(void)
 }
 
 
+#if defined(__i386__)
+#define DB_VALID_ADDR(_a) \
+    ((_a) <= (PAGE_OFFSET - 4))
+#elif defined(__x86_64__)
+#define DB_VALID_ADDR(_a) \
+    ((_a) >= HYPERVISOR_VIRT_END) || ((_a) <= (HYPERVISOR_VIRT_START-8))
+#endif
 long set_debugreg(struct exec_domain *p, int reg, unsigned long value)
 {
     int i;
@@ -845,22 +868,22 @@ long set_debugreg(struct exec_domain *p, int reg, unsigned long value)
     switch ( reg )
     {
     case 0: 
-        if ( value > (PAGE_OFFSET-4) ) return -EPERM;
+        if ( !DB_VALID_ADDR(value) ) return -EPERM;
         if ( p == current ) 
             __asm__ ( "mov %0, %%db0" : : "r" (value) );
         break;
     case 1: 
-        if ( value > (PAGE_OFFSET-4) ) return -EPERM;
+        if ( !DB_VALID_ADDR(value) ) return -EPERM;
         if ( p == current ) 
             __asm__ ( "mov %0, %%db1" : : "r" (value) );
         break;
     case 2: 
-        if ( value > (PAGE_OFFSET-4) ) return -EPERM;
+        if ( !DB_VALID_ADDR(value) ) return -EPERM;
         if ( p == current ) 
             __asm__ ( "mov %0, %%db2" : : "r" (value) );
         break;
     case 3:
-        if ( value > (PAGE_OFFSET-4) ) return -EPERM;
+        if ( !DB_VALID_ADDR(value) ) return -EPERM;
         if ( p == current ) 
             __asm__ ( "mov %0, %%db3" : : "r" (value) );
         break;
index 304f6d31884f4a870726768ad64c35f60050f9fb..d9d00cc3c6dc90c3fac37ef6c75f27391f27c125 100644 (file)
@@ -212,9 +212,10 @@ long do_stack_switch(unsigned long ss, unsigned long esp)
 
 
 /* Returns TRUE if given descriptor is valid for GDT or LDT. */
-int check_descriptor(unsigned long *d)
+int check_descriptor(struct desc_struct *d)
 {
-    unsigned long base, limit, a = d[0], b = d[1];
+    unsigned long base, limit;
+    u32 a = d->a, b = d->b;
 
     /* A not-present descriptor will always fault, so is safe. */
     if ( !(b & _SEGMENT_P) ) 
@@ -298,8 +299,8 @@ int check_descriptor(unsigned long *d)
             if ( !(b & _SEGMENT_G) )
                 goto bad; /* too dangerous; too hard to work out... */
             limit = (limit >> 12) - 1;
-            d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff;
-            d[1] &= ~0xf0000; d[1] |= limit & 0xf0000;
+            d->a &= ~0x0ffff; d->a |= limit & 0x0ffff;
+            d->b &= ~0xf0000; d->b |= limit & 0xf0000;
         }
     }
 
@@ -310,175 +311,6 @@ int check_descriptor(unsigned long *d)
 }
 
 
-void destroy_gdt(struct exec_domain *ed)
-{
-    int i;
-    unsigned long pfn;
-
-    for ( i = 0; i < 16; i++ )
-    {
-        if ( (pfn = l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i])) != 0 )
-            put_page_and_type(&frame_table[pfn]);
-        ed->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
-    }
-}
-
-
-long set_gdt(struct exec_domain *ed, 
-             unsigned long *frames,
-             unsigned int entries)
-{
-    struct domain *d = ed->domain;
-    /* NB. There are 512 8-byte entries per GDT page. */
-    int i = 0, nr_pages = (entries + 511) / 512;
-    struct desc_struct *vgdt;
-    unsigned long pfn;
-
-    /* Check the first page in the new GDT. */
-    if ( (pfn = frames[0]) >= max_page )
-        goto fail;
-
-    /* The first page is special because Xen owns a range of entries in it. */
-    if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
-    {
-        /* GDT checks failed: try zapping the Xen reserved entries. */
-        if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
-            goto fail;
-        vgdt = map_domain_mem(pfn << PAGE_SHIFT);
-        memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
-               NR_RESERVED_GDT_ENTRIES*8);
-        unmap_domain_mem(vgdt);
-        put_page_and_type(&frame_table[pfn]);
-
-        /* Okay, we zapped the entries. Now try the GDT checks again. */
-        if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
-            goto fail;
-    }
-
-    /* Check the remaining pages in the new GDT. */
-    for ( i = 1; i < nr_pages; i++ )
-        if ( ((pfn = frames[i]) >= max_page) ||
-             !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
-            goto fail;
-
-    /* Copy reserved GDT entries to the new GDT. */
-    vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
-    memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY, 
-           gdt_table + FIRST_RESERVED_GDT_ENTRY, 
-           NR_RESERVED_GDT_ENTRIES*8);
-    unmap_domain_mem(vgdt);
-
-    /* Tear down the old GDT. */
-    destroy_gdt(ed);
-
-    /* Install the new GDT. */
-    for ( i = 0; i < nr_pages; i++ )
-        ed->arch.perdomain_ptes[i] =
-            mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
-
-    SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
-    SET_GDT_ENTRIES(ed, entries);
-
-    return 0;
-
- fail:
-    while ( i-- > 0 )
-        put_page_and_type(&frame_table[frames[i]]);
-    return -EINVAL;
-}
-
-
-long do_set_gdt(unsigned long *frame_list, unsigned int entries)
-{
-    int nr_pages = (entries + 511) / 512;
-    unsigned long frames[16];
-    long ret;
-
-    if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) ) 
-        return -EINVAL;
-    
-    if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
-        return -EFAULT;
-
-    LOCK_BIGLOCK(current->domain);
-
-    if ( (ret = set_gdt(current, frames, entries)) == 0 )
-    {
-        local_flush_tlb();
-        __asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
-    }
-
-    UNLOCK_BIGLOCK(current->domain);
-
-    return ret;
-}
-
-
-long do_update_descriptor(
-    unsigned long pa, unsigned long word1, unsigned long word2)
-{
-    unsigned long *gdt_pent, pfn = pa >> PAGE_SHIFT, d[2];
-    struct pfn_info *page;
-    struct exec_domain *ed;
-    long ret = -EINVAL;
-
-    d[0] = word1;
-    d[1] = word2;
-
-    LOCK_BIGLOCK(current->domain);
-
-    if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(d) ) {
-        UNLOCK_BIGLOCK(current->domain);
-        return -EINVAL;
-    }
-
-    page = &frame_table[pfn];
-    if ( unlikely(!get_page(page, current->domain)) ) {
-        UNLOCK_BIGLOCK(current->domain);
-        return -EINVAL;
-    }
-
-    /* Check if the given frame is in use in an unsafe context. */
-    switch ( page->u.inuse.type_info & PGT_type_mask )
-    {
-    case PGT_gdt_page:
-        /* Disallow updates of Xen-reserved descriptors in the current GDT. */
-        for_each_exec_domain(current->domain, ed) {
-            if ( (l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[0]) == pfn) &&
-                 (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
-                 (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
-                goto out;
-        }
-        if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
-            goto out;
-        break;
-    case PGT_ldt_page:
-        if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
-            goto out;
-        break;
-    default:
-        if ( unlikely(!get_page_type(page, PGT_writable_page)) )
-            goto out;
-        break;
-    }
-
-    /* All is good so make the update. */
-    gdt_pent = map_domain_mem(pa);
-    memcpy(gdt_pent, d, 8);
-    unmap_domain_mem(gdt_pent);
-
-    put_page_type(page);
-
-    ret = 0; /* success */
-
- out:
-    put_page(page);
-
-    UNLOCK_BIGLOCK(current->domain);
-
-    return ret;
-}
-
 #ifdef MEMORY_GUARD
 
 void *memguard_init(void *heap_start)
index 153ae6ad6f71b43722a7e0ec181a44be32fdc662..132d8adad3e11de347e07d95dc18269b05ff1adb 100644 (file)
@@ -28,8 +28,8 @@ ENTRY(hypercall)
         SAVE_ALL
         movq  %r10,%rcx
         andq  $(NR_hypercalls-1),%rax
-        leaq  SYMBOL_NAME(hypercall_table)(%rip),%rcx
-        callq *(%rcx,%rax,8)
+        leaq  SYMBOL_NAME(hypercall_table)(%rip),%rbx
+        callq *(%rbx,%rax,8)
         RESTORE_ALL
         addq  $8,%rsp
         popq  %rcx
@@ -147,7 +147,7 @@ ENTRY(nmi)
         SAVE_ALL
         inb   $0x61,%al
         movl  %eax,%esi # reason
-        movl  %esp,%edi # regs
+        movq  %rsp,%rdi # regs
         call  SYMBOL_NAME(do_nmi)
        jmp   restore_all_xen
 
index bf6927f019e279e88cf5be540a7be8baf2f52e49..08f9e8298021ad38e390ca6495476390b62058fe 100644 (file)
@@ -240,99 +240,38 @@ long do_stack_switch(unsigned long ss, unsigned long esp)
 
 
 /* Returns TRUE if given descriptor is valid for GDT or LDT. */
-int check_descriptor(unsigned long *d)
+int check_descriptor(struct desc_struct *d)
 {
-    unsigned long base, limit, a = d[0], b = d[1];
+    u32 a = d->a, b = d->b;
 
     /* A not-present descriptor will always fault, so is safe. */
     if ( !(b & _SEGMENT_P) ) 
         goto good;
 
-    /*
-     * We don't allow a DPL of zero. There is no legitimate reason for 
-     * specifying DPL==0, and it gets rather dangerous if we also accept call 
-     * gates (consider a call gate pointing at another guestos descriptor with 
-     * DPL 0 -- this would get the OS ring-0 privileges).
-     */
-    if ( (b & _SEGMENT_DPL) == 0 )
+    /* The guest can only safely be executed in ring 3. */
+    if ( (b & _SEGMENT_DPL) != 3 )
         goto bad;
 
-    if ( !(b & _SEGMENT_S) )
-    {
-        /*
-         * System segment:
-         *  1. Don't allow interrupt or trap gates as they belong in the IDT.
-         *  2. Don't allow TSS descriptors or task gates as we don't
-         *     virtualise x86 tasks.
-         *  3. Don't allow LDT descriptors because they're unnecessary and
-         *     I'm uneasy about allowing an LDT page to contain LDT
-         *     descriptors. In any case, Xen automatically creates the
-         *     required descriptor when reloading the LDT register.
-         *  4. We allow call gates but they must not jump to a private segment.
-         */
-
-        /* Disallow everything but call gates. */
-        if ( (b & _SEGMENT_TYPE) != 0xc00 )
-            goto bad;
-
-#if 0
-        /* Can't allow far jump to a Xen-private segment. */
-        if ( !VALID_CODESEL(a>>16) )
-            goto bad;
-#endif
+    /* Any code or data segment is okay. No base/limit checking. */
+    if ( (b & _SEGMENT_S) )
+        goto good;
 
-        /* Reserved bits must be zero. */
-        if ( (b & 0xe0) != 0 )
-            goto bad;
-        
-        /* No base/limit check is needed for a call gate. */
+    /* Invalid type 0 is harmless. It is used for 2nd half of a call gate. */
+    if ( (b & _SEGMENT_TYPE) == 0x000 )
         goto good;
-    }
-    
-    /* Check that base is at least a page away from Xen-private area. */
-    base  = (b&(0xff<<24)) | ((b&0xff)<<16) | (a>>16);
-    if ( base >= (PAGE_OFFSET - PAGE_SIZE) )
-        goto bad;
 
-    /* Check and truncate the limit if necessary. */
-    limit = (b&0xf0000) | (a&0xffff);
-    limit++; /* We add one because limit is inclusive. */
-    if ( (b & _SEGMENT_G) )
-        limit <<= 12;
+    /* Everything but a call gate is discarded here. */
+    if ( (b & _SEGMENT_TYPE) != 0xc00 )
+        goto bad;
 
-    if ( (b & (_SEGMENT_CODE | _SEGMENT_EC)) == _SEGMENT_EC )
-    {
-        /*
-         * Grows-down limit check. 
-         * NB. limit == 0xFFFFF provides no access      (if G=1).
-         *     limit == 0x00000 provides 4GB-4kB access (if G=1).
-         */
-        if ( (base + limit) > base )
-        {
-            limit = -(base & PAGE_MASK);
-            goto truncate;
-        }
-    }
-    else
-    {
-        /*
-         * Grows-up limit check.
-         * NB. limit == 0xFFFFF provides 4GB access (if G=1).
-         *     limit == 0x00000 provides 4kB access (if G=1).
-         */
-        if ( ((base + limit) <= base) || 
-             ((base + limit) > PAGE_OFFSET) )
-        {
-            limit = PAGE_OFFSET - base;
-        truncate:
-            if ( !(b & _SEGMENT_G) )
-                goto bad; /* too dangerous; too hard to work out... */
-            limit = (limit >> 12) - 1;
-            d[0] &= ~0x0ffff; d[0] |= limit & 0x0ffff;
-            d[1] &= ~0xf0000; d[1] |= limit & 0xf0000;
-        }
-    }
+    /* Can't allow far jump to a Xen-private segment. */
+    if ( !VALID_CODESEL(a>>16) )
+        goto bad;
 
+    /* Reserved bits must be zero. */
+    if ( (b & 0xe0) != 0 )
+        goto bad;
+        
  good:
     return 1;
  bad:
@@ -340,159 +279,6 @@ int check_descriptor(unsigned long *d)
 }
 
 
-void destroy_gdt(struct exec_domain *ed)
-{
-    int i;
-    unsigned long pfn;
-
-    for ( i = 0; i < 16; i++ )
-    {
-        if ( (pfn = l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i])) != 0 )
-            put_page_and_type(&frame_table[pfn]);
-        ed->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
-    }
-}
-
-
-long set_gdt(struct exec_domain *ed, 
-             unsigned long *frames,
-             unsigned int entries)
-{
-    struct domain *d = ed->domain;
-    /* NB. There are 512 8-byte entries per GDT page. */
-    int i = 0, nr_pages = (entries + 511) / 512;
-    struct desc_struct *vgdt;
-    unsigned long pfn;
-
-    /* Check the first page in the new GDT. */
-    if ( (pfn = frames[0]) >= max_page )
-        goto fail;
-
-    /* The first page is special because Xen owns a range of entries in it. */
-    if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
-    {
-        /* GDT checks failed: try zapping the Xen reserved entries. */
-        if ( !get_page_and_type(&frame_table[pfn], d, PGT_writable_page) )
-            goto fail;
-        vgdt = map_domain_mem(pfn << PAGE_SHIFT);
-        memset(vgdt + FIRST_RESERVED_GDT_ENTRY, 0,
-               NR_RESERVED_GDT_ENTRIES*8);
-        unmap_domain_mem(vgdt);
-        put_page_and_type(&frame_table[pfn]);
-
-        /* Okay, we zapped the entries. Now try the GDT checks again. */
-        if ( !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
-            goto fail;
-    }
-
-    /* Check the remaining pages in the new GDT. */
-    for ( i = 1; i < nr_pages; i++ )
-        if ( ((pfn = frames[i]) >= max_page) ||
-             !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
-            goto fail;
-
-    /* Copy reserved GDT entries to the new GDT. */
-    vgdt = map_domain_mem(frames[0] << PAGE_SHIFT);
-    memcpy(vgdt + FIRST_RESERVED_GDT_ENTRY, 
-           gdt_table + FIRST_RESERVED_GDT_ENTRY, 
-           NR_RESERVED_GDT_ENTRIES*8);
-    unmap_domain_mem(vgdt);
-
-    /* Tear down the old GDT. */
-    destroy_gdt(ed);
-
-    /* Install the new GDT. */
-    for ( i = 0; i < nr_pages; i++ )
-        ed->arch.perdomain_ptes[i] =
-            mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
-
-    SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
-    SET_GDT_ENTRIES(ed, entries);
-
-    return 0;
-
- fail:
-    while ( i-- > 0 )
-        put_page_and_type(&frame_table[frames[i]]);
-    return -EINVAL;
-}
-
-
-long do_set_gdt(unsigned long *frame_list, unsigned int entries)
-{
-    int nr_pages = (entries + 511) / 512;
-    unsigned long frames[16];
-    long ret;
-
-    if ( (entries <= LAST_RESERVED_GDT_ENTRY) || (entries > 8192) ) 
-        return -EINVAL;
-    
-    if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
-        return -EFAULT;
-
-    if ( (ret = set_gdt(current, frames, entries)) == 0 )
-    {
-        local_flush_tlb();
-        __asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
-    }
-
-    return ret;
-}
-
-
-long do_update_descriptor(
-    unsigned long pa, unsigned long word1, unsigned long word2)
-{
-    unsigned long *gdt_pent, pfn = pa >> PAGE_SHIFT, d[2];
-    struct pfn_info *page;
-    long ret = -EINVAL;
-
-    d[0] = word1;
-    d[1] = word2;
-
-    if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(d) )
-        return -EINVAL;
-
-    page = &frame_table[pfn];
-    if ( unlikely(!get_page(page, current->domain)) )
-        return -EINVAL;
-
-    /* Check if the given frame is in use in an unsafe context. */
-    switch ( page->u.inuse.type_info & PGT_type_mask )
-    {
-    case PGT_gdt_page:
-        /* Disallow updates of Xen-reserved descriptors in the current GDT. */
-        if ( (l1_pgentry_to_pagenr(current->arch.perdomain_ptes[0]) == pfn) &&
-             (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
-             (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
-            goto out;
-        if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
-            goto out;
-        break;
-    case PGT_ldt_page:
-        if ( unlikely(!get_page_type(page, PGT_ldt_page)) )
-            goto out;
-        break;
-    default:
-        if ( unlikely(!get_page_type(page, PGT_writable_page)) )
-            goto out;
-        break;
-    }
-
-    /* All is good so make the update. */
-    gdt_pent = map_domain_mem(pa);
-    memcpy(gdt_pent, d, 8);
-    unmap_domain_mem(gdt_pent);
-
-    put_page_type(page);
-
-    ret = 0; /* success */
-
- out:
-    put_page(page);
-    return ret;
-}
-
 #ifdef MEMORY_GUARD
 
 #define ALLOC_PT(_level) \
index 34934faad8020d5d1e3d0edb25480d32a5c5b28c..81e60a05fe621c26f2921d9335b5174082397489 100644 (file)
@@ -219,7 +219,7 @@ static inline int get_page_and_type(struct pfn_info *page,
     ASSERT(((_p)->count_info & PGC_count_mask) != 0);          \
     ASSERT(page_get_owner(_p) == (_d))
 
-int check_descriptor(unsigned long *d);
+int check_descriptor(struct desc_struct *d);
 
 /*
  * Use currently-executing domain's pagetables on the specified CPUs.
index d03ac9ffb14841cae67ddd378521d4af612bc488..f4bac0a150f62c2edf23ff70ae77708361ea1da1 100644 (file)
@@ -9,7 +9,23 @@
 
 #ifdef __x86_64__
 
-#define do_multicall_call(_call) BUG()
+#define do_multicall_call(_call)                         \
+    do {                                                 \
+        __asm__ __volatile__ (                           \
+            "movq  "STR(MULTICALL_op)"(%0),%%rax; "      \
+            "andq  $("STR(NR_hypercalls)"-1),%%rax; "    \
+            "leaq  "STR(hypercall_table)"(%%rip),%%rdi; "\
+            "leaq  (%%rdi,%%rax,8),%%rax; "              \
+            "movq  "STR(MULTICALL_arg0)"(%0),%%rdi; "    \
+            "movq  "STR(MULTICALL_arg1)"(%0),%%rsi; "    \
+            "movq  "STR(MULTICALL_arg2)"(%0),%%rdx; "    \
+            "movq  "STR(MULTICALL_arg3)"(%0),%%rcx; "    \
+            "movq  "STR(MULTICALL_arg4)"(%0),%%r8; "     \
+            "callq *(%%rax); "                           \
+            "movq  %%rax,"STR(MULTICALL_result)"(%0); "  \
+            : : "b" (_call)                              \
+            : "rax", "rdi", "rsi", "rdx", "rcx", "r8" ); \
+    } while ( 0 )
 
 #else